package com.qd.panda.service.card;

import cn.hutool.core.math.Money;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cdqidi.exception.ApiException;
import com.cdqidi.util.JacksonUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.qd.common.panda.constant.PandaConstant;
import com.qd.common.panda.domain.entity.card.UserCardDTO;
import com.qd.common.panda.domain.entity.card.UserCardQueryDTO;
import com.qd.common.panda.domain.entity.card.third.ThirdPartyDTO;
import com.qd.common.panda.domain.entity.card.third.sync.ThirdPartyListDTO;
import com.qd.common.sys.util.SecurityUtils;
import com.qd.panda.model.CardInfo;
import com.qd.panda.model.UserCard;
import com.qd.panda.service.card.third.ThirdPartyService;
import com.qd.panda.service.card.third.sync.ThirdPartyListService;
import com.qd.panda.service.stroke.BigDecimalUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class UserCardHolderService {
    private final UserCardService userCardService;
    private final CardInfoService cardInfoService;
    private final ThirdPartyService thirdPartyService;
    private final ThirdPartyListService thirdPartyListService;

    public BigDecimal buildCard(String cardId, BigDecimal price, String useBrand) {
        //计算卡卷优惠
        CardInfo cardInfo = validatorAndGetCardInfo(cardId, price, PandaConstant.CARD_TYPE_GAS, useBrand);
        BigDecimal amount;
        switch (cardInfo.getDiscountMethod()) {
            case PandaConstant.DISCOUNT_METHOD_1:
                amount = BigDecimalUtil.calculatePrice(price, cardInfo.getDiscount()).getCalculatePrice();
                break;
            case PandaConstant.DISCOUNT_METHOD_2:
            case PandaConstant.DISCOUNT_METHOD_3:
                amount = new Money(price).subtract(new Money(cardInfo.getDiscountAmount())).getAmount();
                break;
            default:
                throw new ApiException("不支持的优惠卷类型");
        }
        return amount;
    }

    public CardInfo validatorAndGetCardInfo(String cardId, BigDecimal price, String cardType, String useBrand) {
        if (!StringUtils.hasLength(cardId)) {
            throw new ApiException("优惠劵ID不能为空");
        }
        String userId = SecurityUtils.getLoginUser().getUserId();
        UserCard userCard = Optional.ofNullable(userCardService.getById(cardId)).orElseThrow(() -> new ApiException("优惠劵ID值错误"));
        if (!userCard.getUserId().equals(userId)) {
            throw new ApiException("没有权限使用");
        }
        if (LocalDate.now().isAfter(userCard.getValidityEndTime())) {
            throw new ApiException("当前优惠劵已过期，无法使用");
        }
        if (userCard.getState() == PandaConstant.USE_STATE_2) {
            throw new ApiException("当前优惠劵已经使用，请勿重复使用");
        }
        if (userCard.getState() == PandaConstant.USE_STATE_3) {
            throw new ApiException("当前优惠劵已过期，无法使用");
        }
        CardInfo cardInfo = Optional.ofNullable(cardInfoService.getById(userCard.getCardMsgId())).orElseThrow(() -> new ApiException("优惠劵信息异常"));
        if (!cardInfo.getCardType().equals(cardType) && !cardInfo.getCardType().equals(PandaConstant.CARD_TYPE_ALL)) {
            throw new ApiException("不支持使用当前类型的优惠劵");
        }
        if (cardInfo.getDiscountMethod().equals(PandaConstant.DISCOUNT_METHOD_2)) {
            if (price.compareTo(cardInfo.getVolumeAmount()) < BigDecimal.ZERO.signum()) {
                throw new ApiException("满减卷的金额未达到指定金额");
            }
        }
        if (StringUtils.hasLength(useBrand)) {
            if (!cardInfo.getUseBrand().equals(PandaConstant.ALL)) {
                if (!cardInfo.getUseBrand().equals(useBrand)) {
                    log.error("当前卡卷不能使用,cardId: {},传入的useBrand： {},卡卷useBrand: {}", cardId, useBrand, cardInfo.getUseBrand());
                    throw new ApiException("当前卡卷不能使用");
                }
            }
        }
        return cardInfo;
    }

    /**
     * 获得可使用的优惠劵列表
     *
     * @param dto 查询参数
     * @return 列表
     */
    @Transactional(readOnly = true)
    public ObjectNode getList(UserCardQueryDTO dto) {
        ObjectMapper objectMapper = JacksonUtil.getObjectMapper();
        ObjectNode objectNode = objectMapper.createObjectNode();
        List<UserCardDTO> list = userCardService.list(dto);
        if (null == list || list.isEmpty()) {
            return null;
        }
        List<UserCardDTO> yesList = new ArrayList<>(list.size());
        List<UserCardDTO> noList = new ArrayList<>(list.size());

        BigDecimal price = new BigDecimal(dto.getPrice());
        for (UserCardDTO userCardDTO : list) {
            if (userCardDTO.getCardInfoDTO().getDiscountMethod().equals(PandaConstant.DISCOUNT_METHOD_2)) {
                if (price.compareTo(userCardDTO.getCardInfoDTO().getVolumeAmount()) < BigDecimal.ZERO.signum()) {
                    noList.add(userCardDTO);
                    continue;
                }
            }
            try {
                BigDecimal amount = buildCard(userCardDTO.getCardId(), price, dto.getUseBrand());
                if (null != amount) {
                    userCardDTO.setPreferentialAmount(amount);
                    userCardDTO.setPreferentialAmountDisplay(amount.stripTrailingZeros().toPlainString());
                }
                //说明是第三方的券码，设置相关信息
                if (StringUtils.hasLength(userCardDTO.getThirdParty())) {
                    buildThirdPartyDTO(userCardDTO);
                }
                yesList.add(userCardDTO);
            } catch (Exception ignored) {
                //可能遇到卡劵已经过期的错误信息
            }
        }
        if (!yesList.isEmpty()) {
            yesList = yesList.stream().sorted(Comparator.comparing(UserCardDTO::getPreferentialAmount)).sorted(Comparator.comparing(UserCardDTO::getValidityEndTime)).collect(Collectors.toList());
        }
        if (!noList.isEmpty()) {
            noList = noList.stream().sorted(Comparator.comparing(UserCardDTO::getValidityEndTime)).collect(Collectors.toList());
        }
        objectNode.putPOJO("availableList", yesList);
        objectNode.putPOJO("noAvailableList", noList);
        return objectNode;
    }

    private void buildThirdPartyDTO(UserCardDTO userCardDTO) {
        ThirdPartyDTO thirdPartyDTO = thirdPartyService.getByIdDto(userCardDTO.getThirdParty());
        if (null != thirdPartyDTO) {
            String param = "event=" + userCardDTO.getEvent() + "&referer=PANDA_PARK&couponCode=" + userCardDTO.getThirdCouponCode();
            thirdPartyDTO.setParams(param);
            userCardDTO.setThirdPartyDTO(thirdPartyDTO);
        }
    }

    /**
     * 获得优惠劵里面的最大优惠金额
     *
     * @param dto 查询条件
     * @return 最大的优惠金额
     */
    @Transactional(readOnly = true)
    public UserCardDTO getCardMax(UserCardQueryDTO dto) {
        List<UserCardDTO> list = userCardService.list(dto);
        if (null == list || list.isEmpty()) {
            return null;
        }
        BigDecimal price = new BigDecimal(dto.getPrice());
        Iterator<UserCardDTO> iterator = list.iterator();
        while (iterator.hasNext()) {
            UserCardDTO userCardDTO = iterator.next();
            if (userCardDTO.getCardInfoDTO().getDiscountMethod().equals(PandaConstant.DISCOUNT_METHOD_2)) {
                if (price.compareTo(userCardDTO.getCardInfoDTO().getVolumeAmount()) < BigDecimal.ZERO.signum()) {
                    iterator.remove();
                    continue;
                }
            }
            try {
                BigDecimal amount = buildCard(userCardDTO.getCardId(), price, dto.getUseBrand());
                if (null != amount) {
                    userCardDTO.setPreferentialAmount(amount);
                }
            } catch (ApiException ignored) {
                iterator.remove();
            }

        }
        return list.stream().min(Comparator.comparing(UserCardDTO::getPreferentialAmount)).orElse(null);
    }

    @Transactional(readOnly = true)
    public UserCardDTO getByIdDto(String cardId) {
        UserCardDTO userCardDTO = userCardService.getByIdDto(cardId);
        if (null != userCardDTO) {
            ThirdPartyListDTO thirdPartyListDTO = thirdPartyListService.getListByCardIdDto(cardId);
            if (null != thirdPartyListDTO) {
                userCardDTO.setThirdParty(thirdPartyListDTO.getThirdParty());
                userCardDTO.setThirdCouponCode(thirdPartyListDTO.getThirdCouponCode());
            }
            buildThirdPartyDTO(userCardDTO);
        }
        return userCardDTO;
    }

    @Transactional(readOnly = true)
    public IPage<UserCardDTO> page(Page<UserCard> page, UserCardQueryDTO dto) {
        IPage<UserCardDTO> iPage = userCardService.page(page, dto);
        Optional.ofNullable(iPage.getRecords()).ifPresent(r -> r.forEach(this::buildThirdPartyDTO));
        return iPage;
    }
}
